﻿using System;

using System.Collections.Generic;
using System.Text;
using Silvermoon.Controls;
using System.IO;
using Silvermoon.Shapes;
using Silvermoon.Utils;
using Silvermoon.IO;
using System.Diagnostics;
using System.Threading;
using Silvermoon.UI;
using Silvermoon.Animations;
using Silvermoon.Images;
using Silvermoon.Windows;
using System.Drawing;

namespace Testing.Browser
{
    public class FolderView : ListBoxBase
    {
        #region fields

        private ItemGroup group;
        private bool editMode;
        private float itemOffset;
        private Thread thread;
        private FolderNode node;
        private List<DirectoryEntry> entries;
        private List<FileItem> lazyItemPool = new List<FileItem>(10);
        private Toolbar editToolbar;

        #endregion
        #region accessors

        public static PropertyAccessor<FolderView, float> ItemOffsetProperty = PropertyAccessor.Register<FolderView, float>("",
            c => c.ItemOffset,
            (c, v) => c.ItemOffset = v
            );

        #endregion
        #region ctor/dtor

        /// <summary>
        /// Initializes the <see cref="FolderView"/> class.
        /// </summary>
        static FolderView()
        {
            MergeStateManager();
        }

        public FolderView()
            : base()
        {
            group = new ItemGroup { ItemHeight = 80 };
            Items.Add(group);

            CreateEditToolbar();
        }

        protected override void Dispose(bool dispose)
        {
            Thread t = thread;
            if (t != null)
            {
                t.Join();
                thread = null;
            }
            foreach (FileItem item in lazyItemPool) item.Dispose();
            lazyItemPool.Clear();
            base.Dispose(dispose);
        }

        #endregion
        #region props

        public FolderNode Node
        {
            get { return node; }
            set { node=value;}
        }


        public List<DirectoryEntry> Entries
        {
            get { return entries; }
            set { entries = value; }
        }

        /// <summary>
        /// Gets or sets the number of entries to display.
        /// </summary>
        public int Count
        {
            get { return group.Count; }
            set { group.Count = value; }
        }

        public ICommand ItemCommand { get; set; }

        /// <summary>
        /// Gets or sets  edit mode for the folder.
        /// </summary>
        public bool EditMode
        {
            get { return editMode; }
            set
            {
                if (editMode != value)
                {
                    editMode = value;
                    OnEditModeChanged();
                }
            }
        }


        /// <summary>
        /// Gets or sets the offset for all items that specifies the indention.
        /// </summary>
        public float ItemOffset
        {
            get { return itemOffset; }
            set
            {
                if (value < 0f) value = 0f; else if (value > 1f) value = 1f;
                if (itemOffset != value)
                {
                    itemOffset = value;
                    Invalidate(InvalidationFlag.UpdateChildren);
                }
            }
        }

        #endregion
        #region methods

        bool editModePan = false;

        protected override void OnBeginPan(PanEventArgs e)
        {
            if (EditMode && e.Direction == PanDirection.Left)
            {
                editModePan = true;
                e.Value = new Point((int)(ItemOffset * FileItem.MaxOffset), 0);
                e.Handled = true;
            }
            else
            {
                editModePan = false;
            }
            base.OnBeginPan(e);
        }


        protected override void OnPan(PanEventArgs e)
        {
            if (EditMode && e.Direction == PanDirection.Left)
            {
                ItemOffset = (float)(e.Value.X) / (float)FileItem.MaxOffset;
                e.Handled = true;
            }
            base.OnPan(e);
        }

        protected override void OnEndPan(EventArgs e)
        {
            if (editModePan) EnsureRestState(true);
            base.OnEndPan(e);
        }

        public override void EnsureRestState(bool animated)
        {
            if (ItemOffset < 0.5f)
            {
                EditMode = false;
            }
            base.EnsureRestState(animated);
        }

        protected override void OnItemRemoved(ItemBase item, ItemGroupBase group)
        {
            if (entries != null)
            {
                base.OnItemRemoved(item, group);
                DirectoryEntry entry = (item as FileItem).Entry;
                lock (entries)
                {
                    entries.Remove(entry);
                }
            }
        }

        private static void MergeStateManager()
        {
            VisualStateManager manager = new VisualStateManager(
                new VisualState("View",
                    new FloatTransition { Property = ItemOffsetProperty, Duration = 350, To = 00, Tracking = TrackMode.Keep, EasingFunction = PowerEase.Out, }
                    ),
                new VisualState("Edit",
                    new FloatTransition { Property = ItemOffsetProperty, Duration = 350, To = 1f, Tracking = TrackMode.Keep, EasingFunction = PowerEase.Out })
                    );

            VisualStateManager.MergeClassManager(typeof(FolderView), manager);
        }

        private void OnEditModeChanged()
        {
            ItemCommand = editMode ? FileCommands.ToggleCheckboxCommand : null;
            SetState(editMode ? "Edit" : "View");
            if (editMode) Window.SetToolbar(editToolbar); else Window.ClearToolbar(editToolbar);
            if (EditModeChanged != null) EditModeChanged(this, EventArgs.Empty);
        }

        private void CreateEditToolbar()
        {
            Toolbar tb = new Toolbar();

            ToolbarButton copyBtn = new ToolbarButton(SysImages.Copy, FileCommands.CopyCommand);
            ToolbarButton deleteBtn = new ToolbarButton(SysImages.RecycleBin, FileCommands.DeleteCommand);
            //ToolbarButton infoButton = new ToolbarButton("?", FileCommands.DetailsCommand);
            ToolbarButton cutBtn = new ToolbarButton(SysImages.Cut, FileCommands.CutCommand);

            tb.Buttons.AddRange(copyBtn, cutBtn, deleteBtn);

            tb.IsMenuButtonVisible = true;
            MenuItem item = new MenuItem("Exit edit mode", FileCommands.ResetEditModeCommand) { Height = 96 };
            tb.MenuItems.Add(item);
            editToolbar = tb;
        }

        protected override bool CanDetach { get { return true; } }

        public override ItemBase GetVirtualItem(ItemGroupBase group, int index)
        {
            DirectoryEntry entry;
            //            lock (entries)
            {
                if (index < 0 || index >= entries.Count) throw new IndexOutOfRangeException();
                entry = entries[index];
            }
            if (entry.IsDirectory) return FileItemFromEntry(entry);

            // get an item from the pool and remove it from the pool:
            int count = lazyItemPool.Count - 1;
            FileItem item;
            if (count >= 0)
            {
                item = lazyItemPool[count];
                lazyItemPool.RemoveAt(count);
                item.InitFromEntry(entry);
            }
            else
            {
                item = FileItemFromEntry(entry);
            }
            return item;
        }

        public override bool OnCanDetachItem(ItemGroupBase group, ItemBase item)
        {
            if (item is FolderItem) return false;
            FileItem fileItem = item as FileItem;

            // do not release a fileitem if it contains additional data, otherwise these data would be lost and even reused falsely:
            if (fileItem.IsSelected || fileItem.IsCut) return false;

            fileItem.Cleanup();
            lazyItemPool.Add(fileItem);
            return true;

        }

        private FileItem FileItemFromEntry(DirectoryEntry entry)
        {
            if (entry.IsDirectory)
            {
                return new FolderItem(node, entry);
            }
            else
            {
                return new FileItem(node, entry);
            }
        }

        public void RemoveFileItem(FileItem item)
        {
            group.RemoveAnimated(item);
        }

        public void AddAnimated(DirectoryEntry entry)
        {
            FileItem item = FileItemFromEntry(entry);
            group.AddAnimated(item);
        }


        #endregion
        #region Events

        public event EventHandler EditModeChanged;

        #endregion

    }
}
